<?php
/**
 * The MIT License
 *
 * Copyright (c) <year> <copyright holders>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @author Damiano Ciarla
 * @package plugin
 * @subpackage entity_manager/class/abstract
 */
abstract class EntityManager_Abstract_Where
{
	/**
	 * Istanza della entity su cui eseguire le operazioni
	 *
	 * @var mixed
	 */
	protected static $object;

	/**
	 * Nome del campo su cui costruire la query
	 *
	 * @var string
	 */
	protected static $field;

	protected static $operator_equal					= "=";
	protected static $operator_not_equal				= "!=";
	protected static $operator_greater					= ">";
	protected static $operator_less						= "<";
	protected static $operator_greater_than_or_equal	= ">=";
	protected static $operator_less_than_or_equal		= "<=";
	protected static $operator_between					= "BETWEEN";
	protected static $operator_not_between				= "NOT BETWEEN";
	protected static $operator_like						= "LIKE";
	protected static $operator_in						= "IN";
	protected static $operator_not_in					= "NOT IN";
	protected static $operator_is_null					= "IS NULL";
	protected static $operator_is_not_null				= "IS NOT NULL";

	/**
	 * Campo uguale ad un determinato valore
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _equal($value)
	{
		return $this->_settingSql(self::$operator_equal, $value);
	}

	/**
	 * Campo diverso da un determinato valore
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _notEqual($value)
	{
		return $this->_settingSql(self::$operator_not_equal, $value);
	}

	/**
	 * Campo maggiore di un determinato valore
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _greater($value)
	{
		return $this->_settingSql(self::$operator_greater, $value);
	}

	/**
	 * Campo minore di un determinato valore
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _less($value)
	{
		return $this->_settingSql(self::$operator_less, $value);
	}

	/**
	 * Campo maggiore o uguale ad un determinato valore
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _greaterThanOrEqual($value)
	{
		return $this->_settingSql(self::$operator_greater_than_or_equal, $value);
	}

	/**
	 * Campo minore o uguale ad un determinato valore
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _lessThanOrEqual($value)
	{
		return $this->_settingSql(self::$operator_less_than_or_equal, $value);
	}

	/**
	 * Setta il campo compreso tra due valori
	 *
	 * @param string $value1 Primo valore della clausola BETWEEN
	 * @param string $value2 Secondo valore della clausola BETWEEN
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _between($value1, $value2)
	{
		return $this->_settingSql(self::$operator_between, array($value1, $value2));
	}

	/**
	 * Setta il campo non compreso tra due valori
	 *
	 * @param string $value1 Primo valore della clausola BETWEEN
	 * @param string $value2 Secondo valore della clausola BETWEEN
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _notBetween($value1, $value2)
	{
		return $this->_settingSql(self::$operator_not_between, array($value1, $value2));
	}

	/**
	 * Campo con la clausola LIKE %valore%
	 *
	 * @param string $value Valore da assegnare alla condizione
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _like($value)
	{
		return $this->_settingSql(self::$operator_like, $value);
	}

	/**
	 * Setta che il campo deve essere compreso all'interno di una lista di valori
	 *
	 * @param string|array $value Lista di valori all'interno di un array o una stringa singola
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _in($value)
	{
		return $this->_settingSql(self::$operator_in, ((!is_array($value)) ? (array)$value : $value));
	}

	/**
	 * Setta che il campo non deve essere compreso all'interno di una lista di valori
	 *
	 * @param string|array $value Lista di valori all'interno di un array o una stringa singola
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _notIn($value)
	{
		return $this->_settingSql(self::$operator_not_in, ((!is_array($value)) ? (array)$value : $value));
	}

	/**
	 * Setta che il campo deve avere un valore NULL
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _isNull()
	{
		return $this->_settingSql(self::$operator_is_null);
	}

	/**
	 * Setta che il campo non deve avere un valore NULL
	 *
	 * @return EntityManager_Function_Find
	 */
	protected function _isNotNull()
	{
		return $this->_settingSql(self::$operator_is_not_null);
	}

	/**
	 * Crea la stringa sql
	 *
	 * @param string $operator Espressione per la query
	 * @param mixed $value Valore da assegnare all'espressione
	 *
	 * @return mixed
	 */
	protected function _settingSql($operator, $value = null)
	{
		$entityProperties = self::$object->_getEntity()->getProperty();

		$table = $entityProperties['ENTITY']['TABLE'];
		$bind  = $this->_getBindType($entityProperties['FIELDS'][self::$field]['properties']['TYPE']);

		switch($operator)
		{
			case self::$operator_between :
			case self::$operator_not_between :

				self::$object->_whereSql .= " AND " . $table . "." . self::$field . " " . $operator . " ? AND ?";

				self::$object->_bindWhereValue[] = array("type" => $bind, "value" => $value[0]);
				self::$object->_bindWhereValue[] = array("type" => $bind, "value" => $value[1]);

				break;

			case self::$operator_in :
			case self::$operator_not_in :

				self::$object->_whereSql .= " AND " . $table . "." . self::$field . " " . $operator . " (";

				foreach($value as $index => $val)
				{
					self::$object->_whereSql .= "?" . (($index < count($value) - 1) ? ", " : "");
					self::$object->_bindWhereValue[] = array("type" => $bind, "value" => $val);
				}

				self::$object->_whereSql .= ")";

				break;

			case self::$operator_is_null :
			case self::$operator_is_not_null :

				self::$object->_whereSql .= " AND " . $table . "." . self::$field . " " . $operator;

				break;

			case self::$operator_like :

				self::$object->_whereSql .= " AND " . $table . "." . self::$field . " " . $operator . " ?";
				self::$object->_bindWhereValue[] = array("type" => $bind, "value" => '%' . $value . '%');

				break;

			default :

				self::$object->_whereSql .= " AND " . $table . "." . self::$field . " " . $operator . " ?";
				self::$object->_bindWhereValue[] = array("type" => $bind, "value" => $value);

				break;
		}

		return self::$object;
	}

	private function _getBindType($fieldType)
	{
		switch($fieldType)
		{
			case "tinyint":
			case "smallint":
			case "mediumint":
			case "int":
			case "bigint":
				return PDO::PARAM_INT;
				break;

			case "boolean":
				return PDO::PARAM_BOOL;
				break;

			case "date":
			case "datetime":
			case "timestamp":
			case "time":
			case "year":

			case "char":
			case "varchar":

			case "tinytext":
			case "text":
			case "mediumtext":
			case "longtext":

			case "binary":
			case "varbinary":

			case "tinyblob":
			case "mediumblob":
			case "blob":
			case "longblob":

			case "enum":
			case "set":
				return PDO::PARAM_STR;
				break;

			default:
				return false;
				break;
		}
	}
}
?>
